/**
  ******************************************************************************
  * @file    mg_driver_uart.c
  * @author  
  * @version V1.1
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT 2020 Shanghai Macrogiga Electronics</center></h2>
  *
  ******************************************************************************
  */
#include "mg_driver_uart.h"
#include "mg_driver_clock.h"
#include "mg_driver_gpio.h"


#define ETBEI  0x02
#define ERBFI  0x01

#define UART_RX_DATA  0x04          /*received data available*/
#define UART_TX_EMPTY 0x02          /*THR empty*/
#define UART_TX_TEMT  0x40          /*TX buffer empty*/
#define UART_RX_DR    0x01          /*RX buffer NOT empty*/

#define UART_BIT_5    0x00
#define UART_BIT_6    0x01
#define UART_BIT_7    0x02
#define UART_BIT_8    0x03

#define UART_STOP_1_BIT    0x00
#define UART_PARITY_ENABLE (0x01<<3)
#define UART_EVEN_CHECK    (0x01<<4)


void UART_Enable_FlowControl(void)
{
    UART_ADDR->MCR = (0x01 << 5) | (0x01 << 1); //AFCE
    
    //enable the pin mux
    GPIO_FunctionSelect(GPIO_MAP_PIN_A1, GPIO_MAP_PIN_FUNC2);//RTS GPA1
    GPIO_FunctionSelect(GPIO_MAP_PIN_A2, GPIO_MAP_PIN_FUNC2);//CTS GPA2
    
    SysCtrl->PA_CONF[1] = 0x04; //output Push-Pull mode
    SysCtrl->PA_CONF[2] = 0x01; //input pull down mode
}

void UART_Set_baudrate(u32 bps)
{
    u16 div;
    
    //enable clk & pin mux
    CLK_SetClockGate(CLK_GATE_UART_EN);
    
    GPIO_FunctionSelect(GPIO_MAP_PIN_A5, GPIO_MAP_PIN_FUNC2);//TX GPA5
    GPIO_FunctionSelect(GPIO_MAP_PIN_A6, GPIO_MAP_PIN_FUNC2);//RX GPA6
    
    SysCtrl->PA_CONF[5] = 0x04; //output Push-Pull mode
    SysCtrl->PA_CONF[6] = 0x02; //input pull up mode
    
    div = 39000000 / 16 / bps; //chip MCU sys clock
    
    UART_ADDR->LCR = 0x80;//enable div writing
    UART_ADDR->RBR_THR_DLL = div;
    UART_ADDR->DLH_IER = (div>>8);
    
    //8 bit + 1 stop + no paircheck
    UART_ADDR->LCR = 0;
    UART_ADDR->LCR = UART_BIT_8 | UART_STOP_1_BIT;
    
    //set fifo level
    UART_ADDR->IIR_FCR = 1;//enable fifo mode, 1 character for RX, empty for Tx
    
    //set irq enable bits
    UART_ADDR->DLH_IER = /*ETBEI | */ERBFI;
//    UART_ADDR->DLH_IER = ETBEI | ERBFI;
}

void UART_ITConfig_TX(u8 enableFlag) //TX empty int
{
    if(enableFlag)
    {
        UART_ADDR->DLH_IER |= ETBEI;
    }
    else
    {
        UART_ADDR->DLH_IER &= (~ETBEI);
    }
}

u32 UART_ReadClearInt(void)
{
    return UART_ADDR->IIR_FCR;
}

u8 UART_Get_RX_Flag(void)
{
    //if(UART_RX_DATA == (UART_ADDR->IIR_FCR & 0x0F))return 1;
    if(UART_ADDR->LSR & UART_RX_DR) return 1; //RX buffer Data ready
    return 0;
}

u8 UART_Get_TX_Flag(void) //get TX done flag
{
    //if(UART_TX_EMPTY == (UART_ADDR->IIR_FCR & 0x0F))return 1; //this seems not work, but what's the reason????
    
    if(UART_ADDR->LSR & UART_TX_TEMT) return 1; //TX buffer empty,TEMT
    
    return 0;
}

void UART_SendOneByte(u8 OneByte)
{   
    UART_ADDR->RBR_THR_DLL = OneByte;
    //while(!UART_Get_TX_Flag()); //wait for empty
}

u8 UART_ReceiveByte(void)
{
    return (u8)(UART_ADDR->RBR_THR_DLL);
}
